package com.huiminpay.transaction.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huiminpay.common.cache.Cache;
import com.huiminpay.common.cache.domain.BusinessException;
import com.huiminpay.common.cache.domain.CommonErrorCode;
import com.huiminpay.common.cache.domain.RedisUtil;
import com.huiminpay.common.cache.util.StringUtil;
import com.huiminpay.transaction.api.PayChannelService;
import com.huiminpay.transaction.convert.PayChannelParamConvert;
import com.huiminpay.transaction.convert.PlatformChannelConvert;
import com.huiminpay.transaction.dto.PayChannelDTO;
import com.huiminpay.transaction.dto.PayChannelParamDTO;
import com.huiminpay.transaction.dto.PlatformChannelDTO;
import com.huiminpay.transaction.entity.AppPlatformChannel;
import com.huiminpay.transaction.entity.PayChannelParam;
import com.huiminpay.transaction.entity.PlatformChannel;
import com.huiminpay.transaction.mapper.AppPlatformChannelMapper;
import com.huiminpay.transaction.mapper.PayChannelMapper;
import com.huiminpay.transaction.mapper.PayChannelParamMapper;
import com.huiminpay.transaction.mapper.PlatformChannelMapper;
import com.sun.corba.se.spi.ior.IdentifiableFactory;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * @ClassName: PayChannelServiceImpl
 * @Package: com.huiminpay.transaction.service
 * @Description: 支付渠道 服务接口实现类
 * @Author 谢同学
 * @Create 2023/11/21 16:29
 * @Version 1.0
 */
@Service
@Log4j2
public class PayChannelServiceImpl implements PayChannelService {

    @Resource
    private PlatformChannelMapper platformChannelMapper;

    @Autowired
    private PayChannelMapper payChannelMapper;

    @Autowired
    private AppPlatformChannelMapper appPlatformChannelMapper;

    @Autowired
    private PayChannelParamMapper payChannelParamMapper;
    @Resource
    private Cache cache;

    /**
     * 获取平台服务类型
     *
     * @return
     * @throws BusinessException
     */
    @Override
    public List<PlatformChannelDTO> queryPlatformChannel() throws BusinessException {
        List<PlatformChannel> platformChannels = platformChannelMapper.selectList(null);
        //entity转dto
        List<PlatformChannelDTO> platformChannelDTOS =
                PlatformChannelConvert.INSTANCE.listentity2listdto(platformChannels);
        return platformChannelDTOS;
    }


    /**
     * 给应用绑定服务类型
     *
     * @param appId                应用id
     * @param platformChannelCodes 服务类型code
     * @throws BusinessException
     */
    @Override
    @Transactional  //事务
    public void bindPlatformChannelForApp(String appId, String platformChannelCodes)
            throws BusinessException {
        int i = queryAppBindPlatformChannel(appId, platformChannelCodes);
        //如果没有绑定则绑定
        if (i == 0) {
            AppPlatformChannel appPlatformChannel = new AppPlatformChannel();
            appPlatformChannel.setAppId(appId);
            appPlatformChannel.setPlatformChannel(platformChannelCodes);
            appPlatformChannelMapper.insert(appPlatformChannel);
        } else {
            throw new BusinessException(CommonErrorCode.E_300011);
        }
    }

    /**
     * 查询应用是否已经绑定了某个服务类型
     *
     * @param appId           应用id
     * @param platformChannel 服务类型
     * @return 已绑定返回1，否则 返回0
     * @throws BusinessException
     */
    @Override
    public int queryAppBindPlatformChannel(String appId, String platformChannel) throws BusinessException {
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(
                new LambdaQueryWrapper<AppPlatformChannel>()
                        .eq(AppPlatformChannel::getAppId, appId)
                        .eq(AppPlatformChannel::getPlatformChannel, platformChannel));
        if (appPlatformChannel == null) {
            return 0;
        }
        return 1;
    }

    /**
     * 根据平台服务类型获取支付渠道列表
     *
     * @param platformChannelCode 服务类型code
     * @return 付渠道列表
     * @throws BusinessException
     */

    @Override
    public List<PayChannelDTO> queryPayChannelByPlatformChannel(
            String platformChannelCode) throws BusinessException {
        return payChannelMapper.selectPayChannelByPlatformChannel(platformChannelCode);
    }


    /**
     * 保存支付渠道参数
     *
     * @param payChannelParamDTO 商户原始支付渠道参数
     * @throws BusinessException
     */
    @Override
    public void savePayChannelParam(PayChannelParamDTO payChannelParamDTO) throws BusinessException {

        //校验数据合法性
        if(payChannelParamDTO == null
                || StringUtil.isBlank(payChannelParamDTO.getAppId())
                || StringUtil.isBlank(payChannelParamDTO.getPlatformChannelCode())
                || StringUtil.isBlank(payChannelParamDTO.getPayChannel())){
            throw new BusinessException(CommonErrorCode.E_300009);
        }
        //根据 appid 和 服务类型code 查询应用与服务类型绑定id
        Long appPlatformChannelId = selectIdByAppPlatformChannel(payChannelParamDTO.getAppId(),
                payChannelParamDTO.getPlatformChannelCode());
        //判断应用是否绑定服务
        if (appPlatformChannelId == null) {
            throw new BusinessException(CommonErrorCode.E_300010);
        }

        //先查询参数信息 如果有 就更新（回显） 没有则添加
        //根据应用与服务类型绑定id和支付渠道查询参数信息
        PayChannelParam payChannelParam = payChannelParamMapper.selectOne(
                new LambdaQueryWrapper<PayChannelParam>()
                        .eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId)
                        .eq(PayChannelParam::getPayChannel, payChannelParamDTO.getPayChannel()));

        //不为空修改
        if (payChannelParam != null) {
            payChannelParam.setChannelName(payChannelParamDTO.getChannelName());
            payChannelParam.setParam(payChannelParamDTO.getParam());
            payChannelParamMapper.updateById(payChannelParam);
        }else {
            //数据转格式 添加
            PayChannelParam entity = PayChannelParamConvert.INSTANCE.dto2entity(payChannelParamDTO);

            entity.setId(null);
            //应用与服务类型绑定id
            entity.setAppPlatformChannelId(appPlatformChannelId);
            payChannelParamMapper.insert(entity);
        }

        //更新缓存
        updateCache(payChannelParamDTO.getAppId(),payChannelParamDTO.getPlatformChannelCode());
    }

    /**
     * 缓存
     * @param appId
     * @param platformChannelCode
     */
    private void updateCache(String appId, String platformChannelCode) {
        //处理redis缓存
        //1、构建key：前缀+应用id+服务渠道code
        String redisKey = RedisUtil.keyBuilder(appId, platformChannelCode);

        //2、查询redis，检查key是否存在
        Boolean exists = cache.exists(redisKey);
        if (exists) {
            //存在，清除
            cache.del(redisKey);
        }
        //3、从数据库查询应用的服务类型对应的实际支付参数，并重新存入缓存
        List<PayChannelParamDTO> paramDTOS = queryPayChannelParamByAppIdAndPlatformcode(appId, platformChannelCode);
        if (paramDTOS !=null) {
            //存入缓存
            cache.set(redisKey, JSON.toJSON(paramDTOS).toString());
        }
    }

    /**
     * 根据应用id和 服务类型code 查询支付渠道参数列表 结果可能是多个(支付宝param 微信param)
     *
     * @param appId           应用id
     * @param platformChannel 服务类型code
     * @return
     */
    @Override
    public List<PayChannelParamDTO> queryPayChannelParamByAppIdAndPlatformcode(String appId, String platformChannel) throws BusinessException {
        //先从redis查询，如果有则返回
        //从缓存查询
        //1.key的构建 如：HM_PAY_PARAM:b910da455bc84514b324656e1088320b:huimin_c2b
        String key = RedisUtil.keyBuilder(appId, platformChannel);
        //是否有缓存
        if (cache.exists(key)) { //有
            //从redis获取支付渠道参数列表（json串）
            String s = cache.get(key);
            //将json串转成 List<PayChannelParamDTO>
           return JSON.parseArray(s,PayChannelParamDTO.class);
        }
        //缓存中没有 则从数据库查询  根据应用和服务类型找到它们绑定id

        //先根据应用id 和 服务类型code 在app_platform_channel 查询 应用与支付渠道绑定的id
        Long appPlatformChannelId = selectIdByAppPlatformChannel(appId, platformChannel);

        if(appPlatformChannelId == null){
            return null;
        }
        //根据应用与支付渠道绑定的id 查询付渠道参数列表
        List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(
                new LambdaQueryWrapper<PayChannelParam>()
                .eq(PayChannelParam::getAppPlatformChannelId,appPlatformChannelId));

        List<PayChannelParamDTO> payChannelParamDTOS = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);
        //保存到redis
        cache.set(key, JSON.toJSONString(payChannelParamDTOS));
        return payChannelParamDTOS;
    }

    /**
     *  获取指定应用指定服务类型下所包含的某个原始支付参数（直接从查询全部里面拿出然后与payChannel进行对比；有缓存相对较快）
     *  @param appId 应用id
     *  @param platformChannel 服务类型code
     *  @param payChannel 支付渠道
     *  @return
     *  @throws BusinessException
     */
    @Override
    public PayChannelParamDTO queryPayChannelParamByAppIdAndPlatformcodeAndPayChannel(String appId, String platformChannel, String payChannel) throws BusinessException {
        //查询所有
        List<PayChannelParamDTO> payChannelParamDTOS = queryPayChannelParamByAppIdAndPlatformcode(appId, platformChannel);
        //把查询出来的结果与payChannel对比
        for (PayChannelParamDTO payChannelParamDTO : payChannelParamDTOS) {
            //相同返回
            if (payChannelParamDTO.getPayChannel().equals(payChannel)) {
                return payChannelParamDTO;
            }
        }
        return null;
    }

    /**
     * 根据 appid 和 服务类型code 查询应用与服务类型绑定id
     *
     * @param appId               应用id
     * @param platformChannelCode 服务类型code
     * @return
     */
    private Long selectIdByAppPlatformChannel(String appId, String platformChannelCode) {
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(
                new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCode));
        //判断是否为空
        if (appPlatformChannel != null) {
            //不为空取出id
            return appPlatformChannel.getId();
        }
        return null;
    }

}
